home *** CD-ROM | disk | FTP | other *** search
- /*
- File: StorageClassShimDS.c
-
- Contains: USB Storage Class Shim Driver Services -
- This file contains all functions related to providing driver services
- to USB UnitTable drivers.
-
- Version: 1.3
-
- Copyright: © 1998-2000 by Apple Computer, Inc., all rights reserved.
- */
- #include <Appearance.h>
- #include <DriverServices.h>
- #include <Gestalt.h>
- #include <Resources.h>
- #include <TextUtils.h>
-
- #include "StorageClassShimDS.h"
- #include "StorageClassShim.h"
-
- #ifndef DIALOG_REZ_NUMBER
- #define DIALOG_REZ_NUMBER 128
- #endif
-
- typedef struct ShimDialogStrings
- {
- Str255 string1;
- Str255 string2;
- Str255 string3;
- } ShimDialogStrings, *ShimDialogStringsPtr;
-
- // These are the Head and Tail pointers for our DriverInfo Linked List.
- // This list handles associating USBDeviceRefs with UnitTable Driver refnums, so
- // Drivers can be removed from the UnitTable when the drive is removed.
- static DriverInfoPtr DriverInfoHeadPtr;
- static DriverInfoPtr DriverInfoTailPtr;
- static Boolean gAppearanceIsPresent = false;
- static CFragConnectionID appearLibID = 0;
-
- // Static variables for the Dialog strings
- static ShimDialogStrings EjectFloppyStrings;
- static ShimDialogStrings EjectCartridgeStrings;
- static ShimDialogStrings ReinsertFloppyStrings;
- static ShimDialogStrings ReinsertCartridgeStrings;
- static ShimDialogStrings ReattachDeviceStrings;
- static Str255 ReattachDeviceHardDiskString3;
- static ShimDialogStrings CartridgeProtectedStrings;
- static NMUPP gHandleDiskRemovedUPP = nil;
- static NMUPP gDisplayNotificationDlogUPP = nil;
- static ModalFilterUPP gEjectDialogFilterUPP = nil;
-
- // Functions used by USBShim to load and release all dialog related resources
- static Boolean LoadDialogResources( void );
- static Boolean ReleaseDialogResources( void );
-
- static OSStatus HandleStorageEvent( DriverRefNum drvrRefNum, UInt16 messageNumber );
- static Boolean IsAppearancePresent( void );
-
- // Functions provided by the Shim for Unit Table drivers to use
- static void InitializeDriverInfoStruct( void );
- static StorageClassShimDispatchTable gShimDispatchTable =
- {
- &HandleStorageEvent,
- &RemoveNotificationDialog
- };
-
-
- // These are the prototypes for internal functions needed to perform our Driver Services
- // These will be used to create the needed UPPs
- static void HandleDiskWasRemovedEvent( NMRecPtr theNMRecPtr );
- static void ActualDisplayNotifcationDialog( NMRecPtr theNMRecPtr );
- static Boolean EjectDialogFilterProc(DialogPtr theDialog, EventRecord *theEvent, DialogItemIndex *itemHit);
-
- // This routine is used to initialize the driver info structure
- Boolean InitializeStorageDriverServices( void )
- {
- // Initialize DriverInfoHeadPtr
- DriverInfoHeadPtr = nil;
- DriverInfoTailPtr = nil;
-
- if ( gHandleDiskRemovedUPP == nil )
- {
- gHandleDiskRemovedUPP = NewNMProc(HandleDiskWasRemovedEvent);
- }
-
- if ( gDisplayNotificationDlogUPP == nil )
- {
- gDisplayNotificationDlogUPP = NewNMProc(ActualDisplayNotifcationDialog);
- }
-
- if ( gEjectDialogFilterUPP == nil )
- {
- gEjectDialogFilterUPP = NewModalFilterProc( EjectDialogFilterProc );
- }
-
- return true;
- }
-
- // This routine is used to release memory used by the driver info structure
- Boolean TerminateStorageDriverServices( void )
- {
- ReleaseDialogResources();
-
- if ( gHandleDiskRemovedUPP != nil )
- {
- DisposeRoutineDescriptor( gHandleDiskRemovedUPP );
- gHandleDiskRemovedUPP = nil;
- }
-
- if ( gDisplayNotificationDlogUPP != nil )
- {
- DisposeRoutineDescriptor( gDisplayNotificationDlogUPP );
- gDisplayNotificationDlogUPP = nil;
- }
-
- if ( gEjectDialogFilterUPP != nil )
- {
- DisposeRoutineDescriptor( gEjectDialogFilterUPP );
- gEjectDialogFilterUPP = nil;
- }
-
- if ( appearLibID != 0 )
- {
- CloseConnection( &appearLibID );
- appearLibID = 0;
- }
-
- return true;
- }
-
- typedef pascal OSErr (AutoSizeDialogProc) ( DialogPtr inDialog );
- typedef AutoSizeDialogProc *AutoSizeDialogProcPtr;
-
- typedef pascal OSErr (StandardAlertProc) (AlertType inAlertType, unsigned char const *inError, unsigned char const *inExplanation,
- const struct AlertStdAlertParamRec *inAlertParam, SInt16 *outItemHit);
- typedef StandardAlertProc *StandardAlertProcPtr;
-
- typedef pascal OSErr (GetDialogItemAsControlProc) ( DialogPtr inDialog, SInt16 inItemNo, ControlHandle *outControl);
- typedef GetDialogItemAsControlProc *GetDialogItemAsControlProcPtr;
-
- static AutoSizeDialogProcPtr myAutoSizeDialogProcPtr;
- static StandardAlertProcPtr myStandardAlertProcPtr;
- static GetDialogItemAsControlProcPtr myGetDialogItemAsControlProcPtr;
-
- Boolean IsAppearancePresent( void )
- {
- if ( gAppearanceIsPresent == false )
- {
- if ( StandardAlert == nil )
- {
- OSStatus err;
- Str255 errMessage;
- CFragSymbolClass symClass;
- void (*entryPoint)();
- THz currentZone;
-
- currentZone = GetZone ();
- SetZone ( SystemZone() );
-
- // We're not linked with AppearanceLib, so find it at runtime.
- err = GetSharedLibrary ("\pAppearanceLib", kPowerPCCFragArch, kLoadCFrag, &appearLibID, (Ptr *)&entryPoint, errMessage);
- if (err != noErr)
- {
- SetZone (currentZone);
- return false;
- }
-
- err = FindSymbol (appearLibID, "\pStandardAlert", (Ptr *)&myStandardAlertProcPtr, &symClass);
- if (err != noErr)
- {
- SetZone (currentZone);
- return false;
- }
-
- err = FindSymbol (appearLibID, "\pAutoSizeDialog", (Ptr *)&myAutoSizeDialogProcPtr, &symClass);
- if (err != noErr)
- {
- SetZone (currentZone);
- return false;
- }
-
- err = FindSymbol (appearLibID, "\pGetDialogItemAsControl", (Ptr *)&myGetDialogItemAsControlProcPtr, &symClass);
- if (err != noErr)
- {
- SetZone (currentZone);
- return false;
- }
-
- SetZone (currentZone);
- LoadDialogResources();
- gAppearanceIsPresent = true;
- }
- else
- {
- // Set our Procedure pointers to the linked in functions
- myStandardAlertProcPtr = StandardAlert;
- myAutoSizeDialogProcPtr = AutoSizeDialog;
- myGetDialogItemAsControlProcPtr = GetDialogItemAsControl;
-
- LoadDialogResources();
- gAppearanceIsPresent = true;
- }
- }
-
- return gAppearanceIsPresent;
- }
-
- // This routine is used by the shim to preload its dialog resources
- Boolean LoadDialogResources( void )
- {
- short myResFile;
- THz currentZone;
- short oldResFileID = 0;
- short dlogRezNum = DIALOG_REZ_NUMBER;
-
- // Get and detach the STR# resource into the system
- // Set the following structures to point to the strings
- SetResLoad(true);
-
- oldResFileID = CurResFile(); // get the current resource file ID
- myResFile = OpenShimResourceFork();
-
- GetIndString(EjectFloppyStrings.string1, dlogRezNum, 1);
- GetIndString(EjectFloppyStrings.string2, dlogRezNum, 2);
- GetIndString(EjectFloppyStrings.string3, dlogRezNum, 3);
- GetIndString(EjectCartridgeStrings.string1, dlogRezNum, 4);
- GetIndString(EjectCartridgeStrings.string2, dlogRezNum, 5);
- GetIndString(EjectCartridgeStrings.string3, dlogRezNum, 6);
- GetIndString(ReinsertFloppyStrings.string1, dlogRezNum, 7);
- GetIndString(ReinsertFloppyStrings.string2, dlogRezNum, 8);
- GetIndString(ReinsertFloppyStrings.string3, dlogRezNum, 9);
- GetIndString(ReinsertCartridgeStrings.string1, dlogRezNum, 10);
- GetIndString(ReinsertCartridgeStrings.string2, dlogRezNum, 11);
- GetIndString(ReinsertCartridgeStrings.string3, dlogRezNum, 12);
- GetIndString(ReattachDeviceStrings.string1, dlogRezNum, 13);
- GetIndString(ReattachDeviceStrings.string2, dlogRezNum, 14);
- GetIndString(ReattachDeviceStrings.string3, dlogRezNum, 15);
- GetIndString(ReattachDeviceHardDiskString3, dlogRezNum, 16);
- GetIndString(CartridgeProtectedStrings.string1, dlogRezNum, 17);
- GetIndString(CartridgeProtectedStrings.string2, dlogRezNum, 18);
- GetIndString(CartridgeProtectedStrings.string3, dlogRezNum, 19);
-
- CloseShimResourceFork();
- UseResFile(oldResFileID); // point at the original file
- return true;
- }
-
- // This routine is used by the shim to release its dialog resources
- Boolean ReleaseDialogResources( void )
- {
- // There currently are no dialog resources that need to be released.
- return true;
- }
-
- StorageClassShimDispatchTablePtr GetShimDispatchTablePtr( void )
- {
- return &gShimDispatchTable;
- }
-
- DriverInfoPtr GetDriverInfoHeadPtr( void )
- {
- return DriverInfoHeadPtr;
- }
-
- DriverInfoPtr FindDriverInfoByDrvrRef( DriverRefNum drvrRefNum )
- {
- DriverInfoPtr currentDriverInfoPtr;
-
- currentDriverInfoPtr = DriverInfoHeadPtr;
- while(currentDriverInfoPtr != nil )
- {
- if(currentDriverInfoPtr->drvrRefNum == drvrRefNum)
- {
- break;
- }
-
- currentDriverInfoPtr = currentDriverInfoPtr->nextDriverInfo;
- }
-
- return currentDriverInfoPtr;
- }
-
- DriverInfoPtr FindDriverInfoByUSBDeviceRef( USBDeviceRef usbDeviceRef )
- {
- DriverInfoPtr currentDriverInfoPtr;
-
- currentDriverInfoPtr = DriverInfoHeadPtr;
- while(currentDriverInfoPtr != nil )
- {
- if(currentDriverInfoPtr->usbDeviceRef == usbDeviceRef)
- {
- break;
- }
-
- currentDriverInfoPtr = currentDriverInfoPtr->nextDriverInfo;
- }
-
- return currentDriverInfoPtr;
- }
-
- DriverInfoPtr AddDriverInfoPtr( void )
- {
- DriverInfoPtr newDriverInfoPtr;
-
- newDriverInfoPtr = (DriverInfoPtr) PoolAllocateResident(sizeof(DriverInfo), true);
-
- if ( newDriverInfoPtr == nil )
- {
- return nil;
- }
-
- // Check if this is the first element that we are creating
- if ( DriverInfoHeadPtr == nil )
- {
- // This is the first element, set the head and tail
- // pointers to this element
- DriverInfoHeadPtr = newDriverInfoPtr;
- DriverInfoTailPtr = newDriverInfoPtr;
- }
- else
- {
- // This is not the first pointer, set the last element
- // to point to this one, and set the tail pointer to this one
- DriverInfoTailPtr->nextDriverInfo = newDriverInfoPtr;
- DriverInfoTailPtr = newDriverInfoPtr;
- }
-
- return newDriverInfoPtr;
- }
-
- void RemoveDriverInfoPtr( DriverInfoPtr oldInfoPtr )
- {
- OSStatus status;
-
- if ( oldInfoPtr == nil )
- {
- return;
- }
-
- // Check to see if the element being removed is the head element
- if( DriverInfoHeadPtr == oldInfoPtr )
- {
- if ( DriverInfoTailPtr == oldInfoPtr )
- {
- // If the Head and Tail points to the element being
- // removed, then it must be the only element. Clear out the Head and Tail pointers
- DriverInfoHeadPtr = nil;
- DriverInfoTailPtr = nil;
- }
- else
- {
- // This is not the only element, set the head to the next element
- DriverInfoHeadPtr = oldInfoPtr->nextDriverInfo;
- }
- }
- else
- {
- // The element being removed is in the middle or end of the list,
- // find the element before it
- DriverInfoPtr currentDriverInfoPtr = DriverInfoHeadPtr;
-
- while ( currentDriverInfoPtr->nextDriverInfo != oldInfoPtr )
- {
- currentDriverInfoPtr = currentDriverInfoPtr->nextDriverInfo;
- }
-
- // We couldn't find the element we are removing in the list, we
- // could have been given a bad pointer. We can't do anything, so just leave.
- if ( currentDriverInfoPtr == nil )
- {
- return;
- }
-
- currentDriverInfoPtr->nextDriverInfo = oldInfoPtr->nextDriverInfo;
- if (DriverInfoTailPtr == oldInfoPtr)
- {
- // If the element being removed is the tail element, update the tail
- // to point to the previous element.
- DriverInfoTailPtr = currentDriverInfoPtr;
- }
- }
-
- // Release the memory for the element
- status = PoolDeallocate( oldInfoPtr );
- }
-
- /******************************** Unit Table Driver Support Functions ******************************************/
- // This routine will initialize a Unit Table Infostructure to be passed to a driver
- void InitializeDriverInfoStruct( void )
- {
- }
-
- // This is the routine that Unit Table drivers call to have the shim put up dialogs to notify the user that action is required
- // The following Notifications are needed:
- // 1) User needs to eject a manually eject floppy
- // 2) The user has removed a manual eject floppy while it was still in use
- // 3) a way for the driver to state a specific message
- // 4) possibly a way for a user to specify a dialog resource and a dialog function
-
- static Boolean removeDialog = false;
-
- OSStatus HandleStorageEvent( DriverRefNum drvrRefNum, UInt16 messageNumber )
- {
- DriverInfoPtr driverInfoPtr;
- OSStatus status;
-
- driverInfoPtr = FindDriverInfoByDrvrRef( drvrRefNum );
-
- if ( messageNumber == kUSBStorageEventManualEjectMediaWasRemoved )
- {
- // Be sure to save the message number for the dialog
- driverInfoPtr->messageNumber = messageNumber;
-
- BlockZero(&driverInfoPtr->theAlertNMRec, sizeof(NMRec));
- driverInfoPtr->theAlertNMRec.qType = nmType;
- driverInfoPtr->theAlertNMRec.nmSound = nil;
- driverInfoPtr->theAlertNMRec.nmRefCon = (UInt32) drvrRefNum; // Save the driver ref for the completion routine
- driverInfoPtr->theAlertNMRec.nmStr = nil;
- driverInfoPtr->theAlertNMRec.nmResp = gHandleDiskRemovedUPP;
- status = NMInstall( &driverInfoPtr->theAlertNMRec );
- }
- else
- {
- status = DisplayNotifcationDialog( drvrRefNum, messageNumber );
- }
-
- return status;
- }
-
- void HandleDiskWasRemovedEvent( NMRecPtr theNMRecPtr )
- {
- DriverInfoPtr driverInfoPtr;
- DriverRefNum drvrRefNum;
- VCBPtr vol;
- Boolean allWereUnmounted = true;
- OSStatus theErr;
-
- // Remove our notification, ignore the result.
- (void) NMRemove( theNMRecPtr );
- drvrRefNum = (DriverRefNum) (theNMRecPtr->nmRefCon);
- driverInfoPtr = FindDriverInfoByDrvrRef( drvrRefNum );
-
- if (driverInfoPtr == nil )
- {
- return;
- }
-
- vol = (VCBPtr) (GetVCBQHdr())->qHead;
-
- while (vol)
- {
- // Check to see if this volume belongs to the driver
- // that is being removed
- if( vol->vcbDRefNum == driverInfoPtr->drvrRefNum)
- {
- short driveNum;
-
- driveNum = vol->vcbDrvNum;
- theErr = UnmountVol( nil, vol->vcbVRefNum );
- Eject( nil, driveNum );
-
- // Check if unmount volume returns a file busy err.
- if ((theErr == fBsyErr) || (theErr == ioErr))
- {
- allWereUnmounted = false;
- }
- }
-
- vol = (VCBPtr) vol->qLink;
- }
-
- if ( allWereUnmounted == false )
- {
- theErr = DisplayNotifcationDialog( drvrRefNum, kUSBStorageEventManualEjectMediaWasRemoved );
- }
- }
-
- OSStatus DisplayNotifcationDialog( DriverRefNum drvrRefNum, UInt16 messageNumber )
- {
- OSStatus status;
- DriverInfoPtr driverInfoPtr;
-
- driverInfoPtr = FindDriverInfoByDrvrRef( drvrRefNum );
-
- // Be sure to save the message number for the dialog
- driverInfoPtr->messageNumber = messageNumber;
-
- BlockZero(&driverInfoPtr->theAlertNMRec, sizeof(NMRec));
- driverInfoPtr->theAlertNMRec.qType = nmType;
- driverInfoPtr->theAlertNMRec.nmSound = (Handle) -1;
- driverInfoPtr->theAlertNMRec.nmRefCon = (UInt32) drvrRefNum; // Save the driver ref for the completion routine
-
- driverInfoPtr->theAlertNMRec.nmStr = nil;
- driverInfoPtr->theAlertNMRec.nmResp = gDisplayNotificationDlogUPP;
-
- driverInfoPtr->hasDialog = true;
- status = NMInstall( &driverInfoPtr->theAlertNMRec );
- return status;
- }
-
- // This is the routine that Unit Table drivers call to notify the shim that the action necessary has occurred and the dialog
- // needs to be removed.
- OSStatus RemoveNotificationDialog( DriverRefNum drvrRefNum, UInt16 messageNumber )
- {
- #pragma unused ( messageNumber )
- DriverInfoPtr driverInfoPtr;
- OSStatus status;
-
- driverInfoPtr = FindDriverInfoByDrvrRef( drvrRefNum );
- if( driverInfoPtr != nil )
- {
- status = NMRemove( &driverInfoPtr->theAlertNMRec );
- removeDialog = true;
- driverInfoPtr->hasDialog = false;
- }
-
- return noErr;
- }
-
- // Appearance Manager Savvy Dialog routines
- Boolean EjectDialogFilterProc(DialogPtr theDialog, EventRecord *theEvent, DialogItemIndex *itemHit)
- {
- if( removeDialog == true )
- {
- *itemHit = kAlertStdAlertOKButton;
- return true;
- }
- else
- {
- return StdFilterProc(theDialog, theEvent, itemHit);
- }
- }
-
- void ActualDisplayNotifcationDialog( NMRecPtr theNMRecPtr )
- {
- SInt16 itemHit;
- DriverInfoPtr driverInfoPtr;
- DriverRefNum drvrRefNum;
- ShimDialogStringsPtr theDialogStringsPtr;
- AlertType theAlertType;
- Str255 alertAStr;
- Str255 alertBStr;
-
- // Remove our notification, ignore the result.
- (void) NMRemove( theNMRecPtr );
- drvrRefNum = (DriverRefNum) (theNMRecPtr->nmRefCon);
- driverInfoPtr = FindDriverInfoByDrvrRef( drvrRefNum );
-
- if (driverInfoPtr == nil )
- {
- return;
- }
-
- if ( IsAppearancePresent() == false )
- {
- return;
- }
-
- // Reattach Drive Dialogs
- removeDialog = false;
-
- driverInfoPtr->theAlertPR.movable = false; // We do not want the alerts movable.
- driverInfoPtr->theAlertPR.helpButton = false; // Currently there is no associated help, so do not show a help button
- driverInfoPtr->theAlertPR.filterProc = gEjectDialogFilterUPP;
- driverInfoPtr->theAlertPR.defaultText = nil; // Do not show an OK button on Stop Alerts
- driverInfoPtr->theAlertPR.cancelText = nil; // Do not show a Cancel button on any Alert
- driverInfoPtr->theAlertPR.otherText = nil; // Do not show a third button on any Alert
- driverInfoPtr->theAlertPR.defaultButton = 0; // set to nil for none
- driverInfoPtr->theAlertPR.defaultButton = kAlertStdAlertOKButton; // Currently it seems Appearance doesn't like this set to zero
- driverInfoPtr->theAlertPR.cancelButton = 0; // We do not have a Cancel button
- driverInfoPtr->theAlertPR.position = kWindowDefaultPosition; // Show in the default position
-
- switch ( driverInfoPtr->messageNumber )
- {
- case kUSBStorageEventRemoveManualEjectMedia:
- {
- if ( (driverInfoPtr->usbSubClass == kUSBStorageUFISubclass) || (driverInfoPtr->usbSubClass == kUSBStorageSFF8070iSubclass))
- {
- theDialogStringsPtr = &EjectFloppyStrings;
- }
- else
- {
- theDialogStringsPtr = &EjectCartridgeStrings;
- }
-
- driverInfoPtr->theAlertPR.defaultText = (unsigned char *) -1; // Use the default OK text
- driverInfoPtr->theAlertPR.defaultButton = kAlertStdAlertOKButton; // Use the standard OK button
- theAlertType = kAlertNoteAlert;
- }
- break;
-
- case kUSBStorageEventManualEjectMediaWasRemoved:
- {
- if ( (driverInfoPtr->usbSubClass == kUSBStorageUFISubclass) || (driverInfoPtr->usbSubClass == kUSBStorageSFF8070iSubclass))
- {
- theDialogStringsPtr = &ReinsertFloppyStrings;
- }
- else
- {
- theDialogStringsPtr = &ReinsertCartridgeStrings;
- }
-
- theAlertType = kAlertStopAlert;
- }
- break;
-
- case kUSBStorageEventDeviceWasRemoved:
- {
- theAlertType = kAlertStopAlert;
- theDialogStringsPtr = &ReattachDeviceStrings;
- }
- break;
-
- case kUSBStorageEventUnusableMediaEjected:
- {
- driverInfoPtr->theAlertPR.defaultText = (unsigned char *) -1; // Use the default OK text
- driverInfoPtr->theAlertPR.defaultButton = kAlertStdAlertOKButton; // Use the standard OK button
- theAlertType = kAlertNoteAlert;
- theDialogStringsPtr = &CartridgeProtectedStrings;
- }
- break;
- }
-
- PStrCopy(alertAStr,theDialogStringsPtr->string1);
- PStrCat(alertAStr,driverInfoPtr->VendorProductStr);
- PStrCat(alertAStr,theDialogStringsPtr->string2);
- PStrCopy(alertBStr,theDialogStringsPtr->string3);
- if ( theAlertType == kAlertNoteAlert)
- {
- // Since it is a NoteAlert, we can use the StandardAlert function to display the dialog
- myStandardAlertProcPtr(theAlertType, alertAStr, alertBStr, &driverInfoPtr->theAlertPR, &itemHit);
- }
- else
- {
- // It is a StopAlert, we must set up our own dialog and display it
- ControlHandle currentItemHand;
- short itemHit;
- DialogPtr stopDialogPtr;
- short myResFile;
- THz currentZone;
- short oldResFileID = 0;
- short dlogRezNum = DIALOG_REZ_NUMBER;
-
- // Set the following structures to point to the strings
- SetResLoad(true);
- oldResFileID = CurResFile(); // get the current resource file ID
-
- myResFile = OpenShimResourceFork();
- stopDialogPtr = GetNewDialog(dlogRezNum, nil, (WindowPtr) -1L );
- if ( stopDialogPtr != nil )
- {
- myGetDialogItemAsControlProcPtr( stopDialogPtr, 2, ¤tItemHand );
- SetDialogItemText( (Handle) currentItemHand, alertAStr );
- myGetDialogItemAsControlProcPtr(stopDialogPtr, 3, ¤tItemHand);
- SetDialogItemText( (Handle) currentItemHand, alertBStr );
- myAutoSizeDialogProcPtr(stopDialogPtr);
- ShowWindow(stopDialogPtr);
- ModalDialog( gEjectDialogFilterUPP, &itemHit );
- CloseWindow( stopDialogPtr );
- DisposeWindow( stopDialogPtr );
- }
-
- UseResFile(oldResFileID); // point at the original file
- CloseShimResourceFork();
- }
- }
-